package com.xiaomi.service.impl;

import com.xiaomi.constant.MessageConstant;
import com.xiaomi.entity.Rule;
import com.xiaomi.entity.Vehicle;
import com.xiaomi.exception.BusinessException;
import com.xiaomi.mapper.RuleMapper;
import com.xiaomi.service.RuleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class RuleServiceImpl implements RuleService {
    @Autowired
    private RuleMapper ruleMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 生成缓存键
     * @param rule
     * @return
     */
    private String generateCacheKey(Rule rule) {
        return "rule:batteryType:" + rule.getBatteryType() + ":ruleCode:" + rule.getRuleCode();
    }
    /**
     * 项目启动时将规则全部存进缓存中
     */
    @PostConstruct
    public void initRule() {
        List<Rule> rules = ruleMapper.selectAll();
        for (Rule rule : rules) {
            String cacheKey = generateCacheKey(rule);
            redisTemplate.opsForValue().set(cacheKey, rule, 1, TimeUnit.HOURS); // 缓存1小时
        }
        log.info("初始化规则缓存完成，共加载 {} 条规则", rules.size());
    }

    /**
     * 根据电池类型获取规则
     * @param batteryType
     * @return
     */
    @Override
    public List<Rule> getRulesByBatteryType(String batteryType) {
        return ruleMapper.selectByBatteryType(batteryType);
    }

    @Override
    public void addRule(Rule rule) {
        rule.setCreateTime(LocalDateTime.now());
        rule.setUpdateTime(LocalDateTime.now());
        ruleMapper.insert(rule);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRule(Long id) {
        // 从数据库中获取规则信息
        Rule rule = ruleMapper.selectById(id);
        if (rule == null) {
            throw new BusinessException(0,MessageConstant.RULE_NOT_FOUND);
        }

        // 删除数据库中的规则
        int result = ruleMapper.deleteById(id);
        if (result <= 0) {
            throw new BusinessException(0,MessageConstant.DELETE_RULE_FAILED);
        }

        // 删除缓存
        String cacheKey = generateCacheKey(rule);
        redisTemplate.delete(cacheKey);

        // 更新电池类型的规则缓存
        String batteryTypeCacheKey = "rules:batteryType:" + rule.getBatteryType();
        List<Rule> cachedRules = (List<Rule>) redisTemplate.opsForValue().get(batteryTypeCacheKey);
        if (cachedRules != null) {
            cachedRules.removeIf(r -> r.getRuleId().equals(id));
            redisTemplate.opsForValue().set(batteryTypeCacheKey, cachedRules, 1, TimeUnit.HOURS);
        }

        log.info("删除规则成功，规则ID: {}", id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRule(Rule rule) {
        // 设置更新时间
        rule.setUpdateTime(LocalDateTime.now());

        // 更新数据库中的规则
        int result = ruleMapper.updateById(rule);
        if (result <= 0) {
            throw new BusinessException(0,MessageConstant.UPDATE_RULE_FAILED);
        }

        // 更新缓存
        String cacheKey = generateCacheKey(rule);
        redisTemplate.opsForValue().set(cacheKey, rule, 1, TimeUnit.HOURS); // 缓存1小时

        // 更新电池类型的规则缓存
        String batteryTypeCacheKey = "rules:batteryType:" + rule.getBatteryType();
        List<Rule> cachedRules = (List<Rule>) redisTemplate.opsForValue().get(batteryTypeCacheKey);
        if (cachedRules != null) {
            for (int i = 0; i < cachedRules.size(); i++) {
                Rule cachedRule = cachedRules.get(i);
                if (cachedRule.getRuleId().equals(rule.getRuleId())) {
                    cachedRules.set(i, rule);
                    break;
                }
            }
            redisTemplate.opsForValue().set(batteryTypeCacheKey, cachedRules, 1, TimeUnit.HOURS);
        } else {
            // 如果缓存中没有，重新加载
            cachedRules = ruleMapper.selectByBatteryType(rule.getBatteryType());
            redisTemplate.opsForValue().set(batteryTypeCacheKey, cachedRules, 1, TimeUnit.HOURS);
        }

        log.info("更新规则成功，规则ID: {}", rule.getRuleId());
    }

    /**
     * 根据规则ID获取规则
     * @param id
     * @return
     */
    @Override
    public Rule getRuleById(Long id) {
        String cacheKey = "rule:id:" + id;
        Rule cachedRule = (Rule) redisTemplate.opsForValue().get(cacheKey);

        if (cachedRule != null) {
            log.info("从缓存中获取规则ID: {}", id);
            return cachedRule;
        }

        Rule rule = ruleMapper.selectById(id);
        if (rule != null) {
            redisTemplate.opsForValue().set(cacheKey, rule, 1, TimeUnit.HOURS); // 缓存1小时
            log.info("从数据库加载规则ID: {} 并缓存", id);
        } else {
            log.warn("未找到规则ID: {}", id);
        }

        return rule;
    }

    /**
     * 获取所有规则
     * @return
     */
    @Override
    public List<Rule> getAllRules() {
        String cacheKey = "rules:all";
        List<Rule> cachedRules = (List<Rule>) redisTemplate.opsForValue().get(cacheKey);

        if (cachedRules != null) {
            log.info("从缓存中获取所有规则");
            return cachedRules;
        }

        List<Rule> rules = ruleMapper.selectAll();
        if (rules != null && !rules.isEmpty()) {
            redisTemplate.opsForValue().set(cacheKey, rules, 1, TimeUnit.HOURS); // 缓存1小时
            log.info("从数据库加载所有规则并缓存");
        } else {
            log.warn("未找到任何规则");
        }

        return rules;
    }

    /**
     * 获取所有电池类型
     * @return
     */
    public List<String> getAllBatteryTypes() {
        return ruleMapper.selectAll().stream()
                .map(Rule::getBatteryType)
                .distinct()
                .collect(Collectors.toList());
    }

    /**
     * 从数据库获取指定电池类型的所有规则
     * @param batteryType
     * @return
     */
    public List<Rule> getRulesByBatteryTypeFromDB(String batteryType) {
        return ruleMapper.selectByBatteryType(batteryType);
    }
}
